home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000 #2
/
Ham Radio 2000 - Volume 2.iso
/
HAMV2
/
TCP_IP
/
TNOS230S
/
PC.C
< prev
next >
Wrap
C/C++ Source or Header
|
1997-07-30
|
29KB
|
1,307 lines
/* OS- and machine-dependent stuff for IBM-PC running MS-DOS
* Copyright 1991 Phil Karn, KA9Q
* Mods by KO4KS
*/
#ifdef MSDOS
#include "global.h"
#include <conio.h>
#include "commands.h"
#include <sys/stat.h>
#include <go32.h>
#include <process.h>
#include <fcntl.h>
#include <stdarg.h>
#include <bios.h>
#include <dpmi.h>
#include <signal.h>
#include "mbuf.h"
#include "proc.h"
#include "iface.h"
#include "session.h"
#include "tty.h"
#include "smtp.h"
#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: pc.c,v 1.25 1997/07/31 00:44:20 root Exp root $";
#endif
#define FP_OFF( fp )( (unsigned )( fp ))
static unsigned Nfiles = 128;
extern void displayStatLine (int offset, int phase, int onlymarquee);
extern void setscreens (int back, int fore, int clr);
static int _go32_dpmi_unchain_protected_mode_interrupt_vector (uint irq, _go32_dpmi_seginfo * info);
static void eoi (void);
void DOSinit (void);
void DOSterm (void);
static void irq0 (void);
static int16 clockbits (void);
static void ctick (void);
static long bioscnt (void);
extern struct proc *Display;
extern char vgaDesired;
extern void volatile *lastkernelevent;
volatile int Tick;
volatile int32 Clock;
static unsigned char orgMode;
#define MAXSCR 20
typedef struct screenstorage {
char *scrptr;
} screenstorage;
static screenstorage DOSscreens[MAXSCR];
static size_t scrsize;
static int saved_break;
struct int_tab {
__dpmi_paddr old; /* Previous handler at this vector */
_go32_dpmi_seginfo new; /* Current handler, with wrapper info */
void (*func) (int); /* Function to call on interrupt */
int arg; /* Arg to pass to interrupt function */
int chain; /* Is interrupt chained to old handler? */
} Int_tab [16];
static const char fkeysyntax1[] =
"key num key num key num key num key num\n"
"f1 59 sf1 84 cf1 94 af1 104 pgup 73\n"
"f2 60 sf2 85 cf2 95 af2 105 pgdn 81\n";
static const char fkeysyntax2[] =
"f3 61 sf3 86 cf3 96 af3 106 home 71\n"
"f4 62 sf4 87 cf4 97 af4 107 end 79\n"
"f5 63 sf5 88 cf5 98 af5 108 arup 72\n";
static const char fkeysyntax3[] =
"f6 64 sf6 89 cf6 99 af6 109 ardn 80\n"
"f7 65 sf7 90 cf7 100 af7 110 ar l 75\n"
"f8 66 sf8 91 cf8 101 af8 111 ar r 77\n";
static const char fkeysyntax4[] =
"f9 67 sf9 92 cf9 102 af9 112 ins 82\n"
"f10 68 sf10 93 cf10 103 af10 113 del 83\n"
"f11 133 sf11 135 cf11 137 af11 139 stab 15\n";
static const char fkeysyntax5[] =
"f12 134 sf12 136 cf12 138 af12 140 cprtsc 114\n"
"cpgup 132 cpgdn 118 chome 119 cend 117\n"
"usage: fkey <key number> [<value> | \"string\"]\n";
static const char fkeyoor[] = "fkey number out of range.\n";
static const char fkeynf[] = "fkey number not found\n";
static const char fkeynoval[] = "fkey %d has no assigned value.\n";
static const char noprompt[] = "\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b";
static const char somemore[] = "--More--";
static FILE *Rawterm;
static char Ttbuf[BUFSIZ];
/* Called at startup time to set up misc I/O related functions */
void
ioinit (int hinit)
{
union REGS inregs;
extern int _fmode;
_fmode = O_BINARY;
/* Get some memory on the heap so interrupt calls to malloc
* won't fail unnecessarily
*/
free (malloc ((uint) hinit));
Rawterm = fopen ("con", "wb");
setbuf (Rawterm, Ttbuf);
/* Increase the size of the file table.
* Note: this causes MS-DOS
* to allocate a block of memory to hold the larger file table.
* By default, this happens right after our program, which means
* any further sbrk() calls from morecore (called from malloc)
* will fail. Hence there is now code in alloc.c that can call
* the MS-DOS allocmem() function to grab additional MS-DOS
* memory blocks that are not contiguous with the program and
* put them on the heap.
*/
inregs.h.ah = 0x67;
inregs.x.bx = Nfiles; /* Up to the base of the socket numbers */
(void) intdos (&inregs, &inregs);
saved_break = getcbrk ();
(void) setcbrk (0);
(void) signal (SIGINT, SIG_IGN);
/* Chain protected mode keyboard interrupt */
LOCK_FUNCTION(kbint);
LOCK_FUNCTION(ksignal);
LOCK_FUNCTION(istate);
LOCK_VARIABLE(Ksig);
LOCK_VARIABLE(lastkernelevent);
(void) setvect (1, 1, (void (*)(int)) kbint, 0);
/* Chain timer interrupt */
LOCK_FUNCTION(ctick);
LOCK_VARIABLE(Tick);
LOCK_VARIABLE(Clock);
(void) setvect (0, 1, (void (*)(int)) ctick, 0);
LOCK_ARRAY(Int_tab);
LOCK_FUNCTION(eoi);
LOCK_FUNCTION(irq0);
}
/* Called just before exiting to restore console state */
void
iostop (void)
{
struct iface *ifp, *iftmp;
void (**fp) (void);
setbuf (Rawterm, NULLCHAR);
(void) setcbrk (saved_break);
for (ifp = Ifaces; ifp != NULL; ifp = iftmp) {
iftmp = ifp->next;
(void) if_detach (ifp);
}
/* Call list of shutdown functions */
for (fp = Shutdown; *fp != NULL; fp++)
(**fp) ();
/* Restore previous timer and keyboard interrupts */
(void) freevect (0);
(void) freevect (1);
}
#ifdef SHELL
/* Spawn subshell */
int
doshell (int argc, char *argv[], void *p)
{
char *command;
int ret;
if (argc == 1 || !stricmp (argv[1], "/c")) {
if ((command = getenv ("COMSPEC")) == NULLCHAR)
command = "COMMAND.COM";
ret = spawnvp (P_WAIT, command, argv);
} else
ret = spawnvp (P_WAIT, argv[1], (argv + 1));
return ret;
}
#endif
#ifdef ALLCMD
/* Spawn mailer as subshell */
int
dobmail (int argc, char *argv[], void *p)
{
char *command;
int ret;
if ((command = getenv ("MAILER")) == NULLCHAR)
command = "BM.EXE";
ret = spawnvp (P_WAIT, command, argv);
smtptick (NULL); /* tickle smtp to send any mail */
return ret;
}
#endif /*ALLCMD*/
static int
kbchar (void)
{
int c;
while ((c = kbraw ()) == 0)
kwait (kbint);
return (c);
}
/* Flush the raw terminal output */
void
rflush (void)
{
(void) fflush (Rawterm);
}
#ifdef ALLCMD
struct funcstr {
unsigned char fkey;
char alloced;
char *fvalue;
};
static struct funcstr fkeys[] =
{
15, 0, NULLCHAR, /* tab + shift */
59, 1, NULLCHAR, /* F1 */
60, 1, NULLCHAR, /* F2 */
61, 1, NULLCHAR, /* F3 */
62, 1, NULLCHAR, /* F4 */
63, 0, NULLCHAR, /* F5 */
64, 0, NULLCHAR, /* F6 */
65, 0, NULLCHAR, /* F7 */
66, 0, NULLCHAR, /* F8 */
67, 0, NULLCHAR, /* F9 */
68, 0, NULLCHAR, /* F10 */
71, 1, NULLCHAR, /* home*/
72, 1, "\033[A", /* up arrow*/
73, 1, NULLCHAR, /* pgup */
75, 1, "\033[D", /* left arrow */
77, 1, "\033[C", /* right arrow */
79, 1, NULLCHAR, /* end */
80, 1, "\033[B", /* down arrow */
81, 1, NULLCHAR, /* pgdn */
82, 1, NULLCHAR, /* ins */
83, 1, NULLCHAR, /* del */
84, 0, NULLCHAR, /* F1 + shift*/
85, 0, NULLCHAR, /* F2 + shift*/
86, 0, NULLCHAR, /* F3 + shift*/
87, 0, NULLCHAR, /* F4 + shift*/
88, 0, NULLCHAR, /* F5 + shift*/
89, 0, NULLCHAR, /* F6 + shift*/
90, 0, NULLCHAR, /* F7 + shift*/
91, 0, NULLCHAR, /* F8 + shift*/
92, 0, NULLCHAR, /* F9 + shift*/
93, 0, NULLCHAR, /* F10 + shift*/
94, 0, NULLCHAR, /* F1 + control*/
95, 0, NULLCHAR, /* F2 + control*/
96, 0, NULLCHAR, /* F3 + control*/
97, 0, NULLCHAR, /* F4 + control*/
98, 0, NULLCHAR, /* F5 + control*/
99, 0, NULLCHAR, /* F6 + control*/
100, 0, NULLCHAR, /* F7 + control*/
101, 0, NULLCHAR, /* F8 + control*/
102, 0, NULLCHAR, /* F9 + control*/
103, 0, NULLCHAR, /* F10 + control*/
104, 0, NULLCHAR, /* F1 + alt*/
105, 0, NULLCHAR, /* F2 + alt*/
106, 0, NULLCHAR, /* F3 + alt*/
107, 0, NULLCHAR, /* F4 + alt*/
108, 0, NULLCHAR, /* F5 + alt*/
109, 0, NULLCHAR, /* F6 + alt*/
110, 0, NULLCHAR, /* F7 + alt*/
111, 0, NULLCHAR, /* F8 + alt*/
112, 0, NULLCHAR, /* F9 + alt*/
113, 0, NULLCHAR, /* F10 + alt*/
114, 0, NULLCHAR, /* PrtSc + ctl*/
117, 0, NULLCHAR, /* end + ctl */
118, 0, NULLCHAR, /* pgup + ctl */
119, 0, NULLCHAR, /* home + ctl */
132, 0, NULLCHAR, /* pgdn + ctl */
133, 0, NULLCHAR, /* F11 */
134, 0, NULLCHAR, /* F12 */
135, 0, NULLCHAR, /* F11 + shift */
136, 0, NULLCHAR, /* F12 + shift */
137, 0, NULLCHAR, /* F11 + control */
138, 0, NULLCHAR, /* F11 + control */
139, 0, NULLCHAR, /* F11 + alt */
140, 0, NULLCHAR, /* F11 + alt */
0, 0, NULLCHAR
};
static char Leftover = 0;
static char *Nextkey = NULLCHAR;
#endif /*ALLCMD*/
/* Read characters from the keyboard, translating them to "real" ASCII.
* If none are ready, block. The F-10 key is special; translate it to -2.
*/
#ifdef ALLCMD
int
kbread (void)
{
int c, i, j;
if ((c = Leftover) != 0) {
Leftover = *Nextkey++;
return c;
}
c = kbchar ();
if ((c & 0xff) == 0) {
/* Lead-in to a special char */
c = (c >> 8) & 0xff; /*lint !e702 */
switch (c) {
case 3: /* NULL (bizzare!) */
c = 0;
break;
case 72: /* UP ARROW key (used as previous history command) */
if (Current == Command) {
c = UPARROW;
break;
}
goto all;
case 80: /* DOWN ARROW key (used as next history command) */
if (Current == Command) {
c = DNARROW;
break;
}
goto all;
case 68: /* F-10 key (used as command-mode escape) */
if (fkeys[10].fvalue == NULLCHAR) {
c = -2;
break;
}
goto all;
case 82: /* INSERT key (used as status line toggle) */
if (fkeys[19].fvalue == NULLCHAR) {
c = -105;
break;
}
goto all;
case 83: /* DELETE key (used as flow mode toggle) */
if (fkeys[20].fvalue == NULLCHAR) {
c = -106;
break;
}
goto all;
case 71: /* HOME key (used to kick this session) */
if (fkeys[11].fvalue == NULLCHAR) {
c = -107;
break;
}
goto all;
case 79: /* END key (used to kill this session) */
if (fkeys[16].fvalue == NULLCHAR) {
c = -108;
break;
}
goto all;
case 73: /* PGUP key (used to toggle to previous session) */
if (fkeys[13].fvalue == NULLCHAR) {
c = -109;
break;
}
goto all;
case 81: /* PGDN key (used to toggle to next session) */
if (fkeys[18].fvalue == NULLCHAR) {
c = -110;
break;
}
goto all;
default: /* Dunno what it is */
all:
if (c > 58 && c < 68) { /* F1 to F9 */
if (fkeys[c - 58].fvalue == NULLCHAR) {
c = (c - 56) * -1; /* NO fkey defined - WG7J */
break;
}
}
for (i = 0; (j = fkeys[i].fkey) != 0; i++)
if (j == c) {
Nextkey = fkeys[i].fvalue;
if (Nextkey == NULLCHAR) {
c = -1;
return c;
}
/* If first char of fvalue is '~'
* switch to command session.
*/
if ((c = *Nextkey++) == '~') {
c = -2;
Leftover = *Nextkey++;
} else {
if (c != 0)
Leftover = *Nextkey++;
else
c = -1;
}
return c;
}
c = -1;
}
} else
c = c & 0xff;
return c;
}
int
dofkey (int argc, char *argv[], void *p)
{
int c, i, j;
char *q, *r;
char str[100];
if (argc == 1) {
tputs (fkeysyntax1);
tputs (fkeysyntax2);
tputs (fkeysyntax3);
tputs (fkeysyntax4);
tputs (fkeysyntax5);
return 0;
}
c = atoi (argv[1]);
if (c == 0 || c > 255) {
tputs (fkeyoor);
return 1;
}
for (j = 0; (i = fkeys[j].fkey) != 0; j++)
if (i == c)
break;
if (i == 0) {
tputs (fkeynf);
return 1;
}
if (argc == 2) {
q = fkeys[j].fvalue;
r = str;
if (q == NULLCHAR)
tprintf (fkeynoval, c);
else {
while (*q)
if (*q < ' ') { /* This is ASCII dependent !! */
*r++ = '^';
*r++ = *q++ + 0x40;
} else
*r++ = *q++;
*r = '\0';
tprintf ("fkey = %s\n", str);
}
return 0;
}
if (argc == 3) {
if (fkeys[j].alloced)
fkeys[j].alloced = 0;
else if (fkeys[j].fvalue != NULLCHAR)
free (fkeys[j].fvalue);
r = str;
q = argv[2];
while (*q) {
if (*q == '^') { /* ^ gives control char next */
q++;
if (*q == '^') {
*r++ = *q++; /* No, he wants a ^ */
} else {
*r++ = *q++ & 0x1f;
}
} else
*r++ = *q++;
}
*r = '\0';
fkeys[j].fvalue = strdup (str);
}
return 0;
}
#else /*ALLCMD*/
int
kbread (void)
{
int c;
if ((c = kbchar ()) == 0) {
/* Lead-in to a special char */
c = kbchar ();
if (Current == Command) { /* Check for command recall */
if (c == 72) /* UP arrow */
return UPARROW;
if (c == 80) /* DOWN arrow */
return DNARROW;
}
switch (c) {
case 3:/* NULL (bizzare!) */
c = 0;
break;
case 68: /* F-10 key (used as command-mode escape) */
c = -2;
break;
case 83: /* DEL key */
c = 0x7f;
break;
default: /* Dunno what it is */
if (c > 58 && c < 68) /* F1 to F9 */
c = (c - 56) * -1;
else
c = -1;
}
}
return c;
}
#endif /*ALLCMD*/
/* Disable hardware interrupt */
int
maskoff (uint irq)
{
if (irq < 8)
setbit (0x21, (char) (1 << irq));
else if (irq < 16) {
irq -= 8;
setbit (0xa1, (char) (1 << irq));
} else
return -1;
return 0;
}
/* Enable hardware interrupt */
int
maskon (uint irq)
{
if (irq < 8)
clrbit (0x21, 1 << irq);
else if (irq < 16) {
irq -= 8;
clrbit (0xa1, 1 << irq);
} else
return -1;
return 0;
}
/* Return 1 if specified interrupt is enabled, 0 if not, -1 if invalid */
int
getmask (unsigned irq)
{
if (irq < 8)
return (inportb (0x21) & (1 << irq)) ? 0 : 1;
else if (irq < 16) {
irq -= 8;
return (inportb (0xa1) & (1 << irq)) ? 0 : 1;
} else
return -1;
}
/* Called from assembler stub linked to BIOS interrupt 1C, called on each
* hardware clock tick. Signal a clock tick to the timer process.
*/
static void
ctick (void)
{
Tick++;
Clock++; /* Keep system time */
ksignal ((void *) &Tick, 1);
}
END_OF_FUNCTION(ctick)
/* Called from the timer process on every tick. NOTE! This function
* can NOT be called at interrupt time because it calls the BIOS
*/
void
pctick (void)
{
long t;
static long oldt = 0; /* Value of bioscnt() on last call */
/* Check for day change */
t = bioscnt ();
if (t < oldt) /* Call the regular DOS time func to handle the midnight flag */
(void) time (NULL);
}
/* Set bit(s) in I/O port */
void
setbit (uint port, uint8 bits)
{
outportb ((int16) port, inportb ((int16) port) | bits);
}
/* Clear bit(s) in I/O port */
void
clrbit (uint port, uint8 bits)
{
outportb ((int16) port, inportb ((int16) port) & ~bits);
}
/* Set or clear selected bits(s) in I/O port */
void
writebit (uint port, uint8 mask, int val)
{
uint8 x;
x = inportb ((int16) port);
if (val)
x |= mask;
else
x &= ~mask;
outportb ((int16) port, x);
}
static void stowit (size_t index, int save, unsigned char attr);
extern unsigned char SCREENwidth, SCREENlength;
extern int STATLINE;
extern struct session *ScreenOwner; /* Session currently displayed */
void
newscreen (struct session *sp)
{
if (sp != NULLSESSION) {
sp->screen = callocw (1, sizeof (struct screen));
sp->screen->statline = uchar(STATLINE);
}
}
void
freescreen (struct session *sp)
{
if (sp == NULLSESSION || sp->screen == NULLSCREEN)
return;
if ((sp->screen->save != NULLCHAR) && sp->screen->save != (char *) 1)
free (sp->screen->save);
free ((char *) sp->screen);
}
/* Save specified session screen and resume console screen */
void
swapscreen (struct session *old, struct session *new)
{
struct text_info tr;
unsigned char attr;
if (old == new)
return; /* Nothing to do */
(void) fflush (Rawterm);
gettextinfo (&tr);
if (old != NULLSESSION) {
/* Save old screen */
if (old->screen->save == NULLCHAR)
old->screen->save = (char *) 1;
old->screen->row = wherey ();
old->screen->col = wherex ();
old->screen->attr = tr.attribute;
if (old->screen->save != NULLCHAR) {
if (old->split) {
window (1, 1, SCREENwidth, SCREENlength);
tr.winbottom = SCREENlength;
}
stowit ((unsigned long) old->index, 1, 0);
/* save it */
}
}
if (new != NULLSESSION) {
/* Load new screen */
if (new->screen->save != NULLCHAR) {
if (new->split)
window (1, 1, SCREENwidth, SCREENlength - 2);
else
window (1, 1, SCREENwidth, SCREENlength);
setscreens ((new->screen->attr >> 4) & 0x07, new->screen->attr & 0x0f, 0);
stowit ((unsigned long) new->index, 0, new->screen->attr);
/* retrieve it */
new->screen->attr &= 0x7f;
/* remove color change bit */
/* if (STATLINE && (Current == Command)) */
window (1, 1 + new->screen->statline, SCREENwidth, SCREENlength - (new->split * 2));
gotoxy (new->screen->col, new->screen->row);
textattr (new->screen->attr);
new->screen->save = NULLCHAR;
} else {
window (1, 1, SCREENwidth, SCREENlength);
clrscr (); /* Start with a fresh slate */
if (new->split) {
new->tsavex = 1;
new->tsavey = 1;
new->bsavex = 1;
new->bsavey = SCREENlength - 1;
window (1, SCREENlength - 1, SCREENwidth, SCREENlength);
gettextinfo (&tr);
attr = ((tr.attribute & 0x0f) << 4) + ((tr.attribute & 0x70) >> 4);
textattr (attr);
clrscr ();
cputs ("_\b");
window (1, 1 + new->screen->statline, SCREENwidth, SCREENlength - 2 - new->screen->statline);
textattr (tr.attribute);
} else
window (1, 1 + new->screen->statline, SCREENwidth, SCREENlength - new->screen->statline);
}
}
ScreenOwner = new;
displayStatLine (0, 1, 0);
alert (Display, 1); /* Wake him up */
}
void
display (int i, void *v1, void *v2)
{
int c;
struct session *sp;
int statsize;
server_disconnect_io ();
/* This is very tricky code. Because the value of "Current" can
* change any time we do a kwait, we have to be careful to detect
* any change and go back and start again.
*/
for ( ; ; ) {
sp = Current;
if (sp->morewait) {
kwait (&sp->row);
if (sp != Current || sp->row <= 0) {
/* Current changed value, or the user
* hasn't really hit a key
*/
continue;
}
/* Erase the prompt */
cprintf (noprompt);
rflush ();
}
sp->morewait = 0;
if ((c = rrecvchar (sp->output)) == EOF) {
/* the alert() in swapscreen will cause this to
* return EOF when current changes
*/
kwait (NULL); /* Prevent a nasty loop */
continue;
}
#ifdef SCREENSAVER
sskick ();
#endif
if (sp->split) {
if (c == 0x0a) {
cputs (Eol);
clreol ();
} else
putch (c);
} else
cprintf ("%c", c);
/* Fix by Ron Murray, vk6zjm */
if (sp->record != NULLFILE) /* Don't save CR if ascii mode */
if (c != '\r' || sockmode (sp->output, -1) != SOCK_ASCII)
putc (c, sp->record);
statsize = 0;
if (sp->screen->statline)
statsize = ((sp == Command) ? getStatlines() : 1);
if (sp->flowmode && c == '\n' && sp->row > 0 && --sp->row == statsize) {
cprintf (somemore);
sp->morewait = 1;
sp->row = 0;
}
}
}
/* Return time since startup in milliseconds. Resolution is improved
* below 55 ms (the clock tick interval) by reading back the instantaneous
* 8254 counter value and combining it with the global clock tick counter.
*
* Reading the 8254 is a bit tricky since a tick could occur asynchronously
* between the two reads. The tick counter is examined before and after the
* hardware counter is read. If the tick counter changes, try again.
* Note: the hardware counter counts down from 65536.
*/
int32
msclock (void)
{
int32 hi;
uint lo;
uint64 x;
do {
hi = rdclock ();
lo = clockbits ();
} while (hi != rdclock ());
x = ((uint64) (uint32) hi << 16) - lo;
return (int32) ((x * 11) / 13125);
}
/* Return clock in seconds */
int32
secclock (void)
{
int32 hi;
uint lo;
uint64 x;
do {
hi = rdclock ();
lo = clockbits ();
} while (hi != rdclock ());
x = ((uint64) (uint32) hi << 16) - lo;
return (int32) ((x * 11) / 13125000);
}
/* Directly read BIOS count of time ticks. This is used instead of
* calling biostime(0,0L). The latter calls BIOS INT 1A, AH=0,
* which resets the midnight overflow flag, losing days on the clock.
*/
static long
bioscnt (void)
{
long rval;
int i_state;
i_state = disable ();
dosmemget (0x46c, sizeof (rval), &rval);
restore (i_state);
return rval;
}
/* Atomic read-and-decrement operation.
* Read the variable pointed to by p. If it is
* non-zero, decrement it. Return the original value.
*/
int
arddec (volatile int *p)
{
int tmp;
int i_state;
i_state = disable ();
tmp = *p;
if (tmp != 0)
(*p)--;
restore (i_state);
return tmp;
}
void
restore (int state)
{
(void) (state ? enable (): disable ());
}
int
istate (void)
{
long flags;
#ifndef _lint
asm ( "pushfl\n\t" /* We save the old ccr, which has interrupt mask bit. */
"popl %0\n\t":"=r" (flags));
#else
flags = 0;
#endif
return (flags >> 9) & 1; /*lint !e704 */
}
END_OF_FUNCTION(istate)
/* This function is called by exit() in the GCC libc. We define
* it here to supersede the one defined in libc's stdio
*/
void
_cleanup (void)
{
}
/* clockbits - Read low order bits of timer 0 (the TOD clock)
* This works only for the 8254 chips used in ATs and 386s.
*
* The timer runs in mode 3 (square wave mode), counting down
* by twos, twice for each cycle. So it is necessary to read back the
* OUTPUT pin to see which half of the cycle we're in. I.e., the OUTPUT
* pin forms the most significant bit of the count. Unfortunately,
* the 8253 in the PC/XT lacks a command to read the OUTPUT pin...
*
* The PC's clock design is soooo brain damaged...
*/
static int16
clockbits (void)
{
int i_state;
unsigned int thestat, count;
do {
i_state = disable ();
outportb (0x43, 0xc2); /* latch timer 0 count and status for reading */
thestat = inportb (0x40); /* get status of timer 0 */
count = inportb (0x40); /* lsb of count */
count |= inportb (0x40) << 8; /* msb of count */
restore (i_state); /* no more chip references */
} while (thestat & 0x40); /* reread if NULL COUNT bit set */
thestat = (thestat & 0x80) << 8; /* Shift OUTPUT to msb of 16-bit word */
count >>= 1; /* count /= 2 */
if (count == 0)
return (int16) (thestat ^ 0x8000); /* return complement of OUTPUT bit */
else
return (int16) (count | thestat); /* Combine OUTPUT with counter */
}
void
kbint (void)
{
ksignal (kbint, 1);
}
END_OF_FUNCTION(kbint)
void
giveup (void)
{
__dpmi_yield ();
}
void
sysreset (void)
{
/* nothing! */
}
int16
lcsum (int16 * buf, int16 cnt)
{
uint32 sum = 0;
while (cnt-- != 0)
sum += *buf++;
while (sum > 65535)
sum = (sum & 0xffff) + (sum >> 16);
return ((sum >> 8) | (sum << 8)) & 0xffff;
}
/* What a crock. All this inelegance should be replaced with something
* that figures out what interrupt is being serviced by reading the 8259.
*/
#define IRQFN(n) static void irq##n (void) { eoi (); (*Int_tab[n].func) (Int_tab[n].arg);}
IRQFN(0)
IRQFN(1)
IRQFN(2)
IRQFN(3)
IRQFN(4)
IRQFN(5)
IRQFN(6)
IRQFN(7)
IRQFN(8)
IRQFN(9)
IRQFN(10)
IRQFN(11)
IRQFN(12)
IRQFN(13)
IRQFN(14)
IRQFN(15)
END_OF_FUNCTION(irq0)
static void (*Vectab[16]) (void) = {
irq0, irq1, irq2, irq3, irq4, irq5, irq6, irq7, irq8, irq9, irq10, irq11,
irq12, irq13, irq14, irq15
};
int
setvect (uint irq, int chain, void (*func) (int), int arg)
{
struct int_tab *ip;
uint intno;
int i;
if (irq > 15)
return -1; /* IRQ out of legal range */
ip = &Int_tab[irq];
if (ip->func != NULL)
return -1; /* Already in use */
/* Convert irq to actual CPU interrupt vector */
intno = (irq < 8) ? irq + 8 : 0x70 + irq - 8;
(void) __dpmi_get_protected_mode_interrupt_vector ((int) intno, &ip->old);
ip->func = func;
ip->arg = arg;
ip->new.pm_offset = (unsigned long) Vectab[irq];
ip->new.pm_selector = (int16) _go32_my_cs ();
ip->chain = chain;
if (chain)
return _go32_dpmi_chain_protected_mode_interrupt_vector ((int) intno, &ip->new);
if ((i = _go32_dpmi_allocate_iret_wrapper (&ip->new)) != 0)
return i;
return _go32_dpmi_set_protected_mode_interrupt_vector ((int) intno, &ip->new);
}
int
freevect (uint irq)
{
struct int_tab *ip;
int i;
if (irq > 15)
return -1; /* IRQ out of legal range */
ip = &Int_tab[irq];
ip->func = NULL;
/* Convert irq to actual CPU interrupt vector */
irq = (irq < 8) ? irq + 8 : 0x70 + irq - 8;
if (ip->chain)
return _go32_dpmi_unchain_protected_mode_interrupt_vector (irq, &ip->new);
if ((i = __dpmi_set_protected_mode_interrupt_vector ((int) irq, &ip->old)) != 0)
return i;
return _go32_dpmi_free_iret_wrapper (&ip->new);
}
/* Re-arm 8259 interrupt controller(s)
* Should be called just after taking an interrupt, instead of just
* before returning. This is because the 8259 inputs are edge triggered, and
* new interrupts arriving during an interrupt service routine might be missed.
*/
static void
eoi (void)
{
/* read in-service register from secondary 8259 */
outportb (0xa0, 0x0b);
if (inportb (0xa0))
outportb (0xa0, 0x20); /* Send EOI to secondary 8259 */
outportb (0x20, 0x20); /* Send EOI to primary 8259 */
}
END_OF_FUNCTION(eoi)
char Hashtab[256];
int16
hash_ip (uint32 ipaddr)
{
int h;
h = ((ipaddr >> 16) & 0xFFFF) ^ (ipaddr & 0xFFFF);
return (int16) uchar(Hashtab[((h >> 8) & 0xFF) ^ (h & 0xFF)]); /*lint !e702 */
}
/* Convert a pointer to a long integer */
long
ptol (void *p)
{
long x;
x = (long) FP_OFF (p);
x |= (long) ((uint32) p << 16); /*lint !e703 */
return x;
}
void
strrev (char *str)
{
char *cp, *save, *cp2;
save = mallocw (strlen (str) + 1);
cp2 = str;
cp = &save[strlen (str)];
*cp-- = 0;
while (*cp2)
*cp-- = *cp2++;
strcpy (str, save);
free (save);
}
long
dostounix (struct date *dp, struct time *tp)
{
static struct tm tm;
struct tm *tx;
time_t now;
tm.tm_year = dp->da_year - 1900;
tm.tm_mon = dp->da_mon - 1;
tm.tm_mday = dp->da_day;
tm.tm_hour = tp->ti_hour;
tm.tm_min = tp->ti_min;
tm.tm_sec = tp->ti_sec;
/* This desperately needs to be fixed. How? */
(void) time (&now);
tx = localtime (&now);
tm.tm_isdst = tx->tm_isdst;
return (long) mktime (&tm);
}
static void
stowit (size_t theindex, int save, unsigned char attr)
{
char *nerf;
register int k, l, split;
register char *cp;
nerf = (char *) mallocw(scrsize);
if (save) {
ScreenRetrieve(nerf);
if (DOSscreens[theindex].scrptr)
free (DOSscreens[theindex].scrptr);
DOSscreens[theindex].scrptr = nerf;
} else {
memcpy (nerf, DOSscreens[theindex].scrptr, scrsize);
if (attr & 0x80) {
attr &= 0x7f;
l = (int) (scrsize / 2);
split = Sessions[theindex].split;
if (split)
l -= 160; /* last 2 lines reversed */
cp = (nerf + 1);
for (k = 0; k < l; k++) {
*cp &= 8; /* keep high video bit */
*cp |= attr;
cp += 2;
}
attr = ((attr & 0x0f) << 4) + ((attr & 0x70) >> 4);
if (split)
for (k = 0; k < 160; k++) {
*cp &= 8; /* keep high video bit */
*cp |= attr;
cp += 2;
}
}
ScreenUpdate(nerf);
free (nerf);
}
}
void DOSinit ()
{
struct text_info tr;
gettextinfo(&tr);
orgMode = tr.currmode;
if (vgaDesired) {
textmode ((int) C4350);
gettextinfo(&tr);
}
SCREENwidth = tr.screenwidth;
SCREENlength = tr.screenheight;
window (1,1,SCREENwidth,SCREENlength);
scrsize = 2 * tr.screenheight * tr.screenwidth;
}
void DOSterm ()
{
int k;
for (k = 0; k < MAXSCR; k++)
if (DOSscreens[k].scrptr)
free (DOSscreens[k].scrptr);
textmode (orgMode);
}
#undef free
/* Written to extend gopint.c in djgpp library */
static int
_go32_dpmi_unchain_protected_mode_interrupt_vector (uint irq, _go32_dpmi_seginfo * info)
{
__dpmi_paddr v;
char *stack;
char *wrapper;
(void) __dpmi_get_protected_mode_interrupt_vector ((int) irq, &v);
/* Sanity check: does the vector point into our program? A bug in gdb
* keeps us from hooking the keyboard interrupt when we run under its
* control. This test catches it.
*/
if (v.selector != _go32_my_cs ())
return -1;
wrapper = (char *) v.offset32;
/* Extract previous vector from the wrapper chainback area */
v.offset32 = *(unsigned long *) (wrapper + 0x5b);
v.selector = *(unsigned short *) (wrapper + 0x5f);
/* Extract stack base from address of _call_count variable in wrapper */
stack = (char *) (*(long *) (wrapper + 0x0F) - 8);
#define STACK_WAS_MALLOCED (1 << 0)
if (*(long *) stack & STACK_WAS_MALLOCED)
free (stack);
free (wrapper);
(void) __dpmi_set_protected_mode_interrupt_vector ((int) irq, &v);
return 0;
}
#endif /* MSDOS */